<?php
namespace Modules\Social\Api\Providers;


use GuzzleHttp\RequestOptions;
use Modules\Social\Api\AccessTokenInterface;
use Modules\Social\Api\ProviderInterface;
use Modules\Social\Api\User;

class FeishuProvider extends AbstractProvider implements ProviderInterface
{

    protected $baseUrl = 'https://open.feishu.cn';

    protected function getAuthUrl($state)
    {
        return $this->buildAuthUrlFromBase($this->baseUrl.'/connect/qrconnect/page/sso/', $state);
    }

    protected function getAppTokenUrl()
    {
        return $this->baseUrl.'/open-apis/auth/v3/app_access_token/internal/';
    }

    /**
     * 获取access_token地址.
     *
     * {@inheritdoc}
     */
    protected function getTokenUrl()
    {
        return $this->baseUrl.'/open-apis/authen/v1/access_token';
    }

    /**
     * {@inheritdoc}
     */
    protected function getCodeFields($state = null)
    {
        $fields = [
            'app_id' => $this->clientId,
            'redirect_uri' => $this->redirectUrl
        ];

        if ($this->usesState()) {
            $fields['state'] = $state;
        }

        return $fields;
    }

    /**
     * @param string $code
     * @return array|mixed
     */
    public function getAccessToken($code = '')
    {
        $response = $this->getHttpClient()->get($this->getAppTokenUrl(), [
            'query' => [
                'app_id' => $this->clientId,
                'app_secret' => $this->clientSecret
            ]
        ]);
        $app_response = json_decode($response->getBody(), true);

        if(isset($app_response['app_access_token'])) {
            $response = $this->getHttpClient()->post($this->getTokenUrl(), [
                RequestOptions::JSON => array_merge(['app_access_token' => $app_response['app_access_token']], $this->getTokenFields($code))
            ]);
            $this->credentialsResponseBody = json_decode($response->getBody(), true);

            return $this->parseAccessToken($this->credentialsResponseBody['data']);
        }
        throw new SocialiteException('app_access_token failed', 400);;
    }

    /**
     * {@inheritdoc}
     */
    protected function getUserByToken(AccessTokenInterface $token)
    {
        $response = $this->getHttpClient()->get($this->baseUrl . '/open-apis/authen/v1/user_info', [
            'headers' => [
                'Content-Type' => 'application/json',
                'Authorization' => 'Bearer '.$token->getToken(),
            ],
            'query' => [
                'user_access_token' => $token->getToken(),
            ]
        ]);
        return json_decode($response->getBody(), true);
    }

    /**
     * {@inheritdoc}
     */
    protected function mapUserToObject(array $user)
    {
        if ($user['code'] != 0) {
            app('log')->info(json_encode($user));
            throw new SocialiteException($user['msg'], $user['code']);
        }
        $user = $user['data'] ?: [];
        return new User([
            'id' => $this->arrayItem($user, 'open_id'),
            'name' => $this->arrayItem($user, 'name'),
            'nickname' => $this->arrayItem($user, 'en_name'),
            'avatar' => $this->arrayItem($user, 'avatar_url'),
            'email' => $this->arrayItem($user, 'email'),
            'mobile' => isset($user['mobile']) ? substr($user['mobile'], -11) : null
        ]);
    }

    /**
     * {@inheritdoc}
     */
    protected function getTokenFields($code)
    {
        return [
            'code' => $code,
            'grant_type' => 'authorization_code'
        ];
    }

    /**
     * {@inheritdoc}
     */
    protected function formatScopes(array $scopes, $scopeSeparator)
    {
        // HACK: unionid is a faker scope for user id
        if (in_array('unionid', $scopes)) {
            unset($scopes[array_search('unionid', $scopes)]);
        }
        return implode($scopeSeparator, $scopes);
    }

}
